package com.googlecode.mailnet.emf.netmodel.ui;

import java.util.LinkedList;
import java.util.List;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;

import com.googlecode.mailnet.emf.netmodel.LinkModel;
import com.googlecode.mailnet.emf.netmodel.NetworkConfigurationModel;
import com.googlecode.mailnet.emf.netmodel.NodeModel;
import com.googlecode.mailnet.emf.netmodel.diagram.edit.parts.LinkModelEditPart;
import com.googlecode.mailnet.emf.netmodel.diagram.edit.parts.LinkModelNameEditPart;
import com.googlecode.mailnet.emf.netmodel.diagram.edit.parts.NetworkConfigurationModelEditPart;
import com.googlecode.mailnet.emf.netmodel.diagram.edit.parts.NodeModelEditPart;
import com.googlecode.mailnet.emf.netmodel.simulation.LinkStatistics;
import com.googlecode.mailnet.emf.netmodel.simulation.NodeStatistics;
import com.googlecode.mailnet.emf.netmodel.simulation.SimulationContext;
import com.googlecode.mailnet.emf.netmodel.simulation.SimulationStatistics;
import com.googlecode.mailnet.info.ILinkInfo;
import com.googlecode.mailnet.info.INodeInfo;

public class InfoTableContentProvider implements IStructuredContentProvider {

	List<InfoTableItem> items = new LinkedList<InfoTableItem>();
	
	Object propertyModel = null;
	
	SimulationContext context;
	@Override
	public Object[] getElements(Object inputElement) {
		return items.toArray();
	}

	@Override
	public void dispose() {
		// TODO Auto-generated method stub

	}
	
	Object input;
	
	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		
		input = newInput;
		
		if (newInput instanceof NodeModelEditPart) {
			NodeModelEditPart editPart = (NodeModelEditPart) newInput;
			NodeModel nodeModel = (NodeModel) editPart.resolveSemanticElement();
			NetworkConfigurationModel configurationModel = (NetworkConfigurationModel) nodeModel.eContainer();
			context = configurationModel.getSimulationContext();
			if (context == null) return;
			INodeInfo info = context.getInfo().getNodeInfoSet().get(context.resolveObject(nodeModel));
			propertyModel = info;
			onNodeInfoInput(info);
		} else if (newInput instanceof LinkModelEditPart) {
			LinkModel model = (LinkModel)((LinkModelEditPart) newInput).resolveSemanticElement();
			NetworkConfigurationModel configurationModel = (NetworkConfigurationModel) model.eContainer();
			context = configurationModel.getSimulationContext();
			if (context == null) return;
			ILinkInfo info = context.getInfo().getLinkInfoSet().get(context.resolveObject(model));
			propertyModel = info;
			onLinkInfoInput(info);
		} else if (newInput instanceof LinkModelNameEditPart) {
			LinkModel model = (LinkModel)((LinkModelNameEditPart) newInput).resolveSemanticElement();
			NetworkConfigurationModel configurationModel = (NetworkConfigurationModel) model.eContainer();
			context = configurationModel.getSimulationContext();
			if (context == null) return;
			ILinkInfo info = context.getInfo().getLinkInfoSet().get(context.resolveObject(model));
			propertyModel = info;
			onLinkInfoInput(info);
		} else if (newInput instanceof NetworkConfigurationModelEditPart) {
			NetworkConfigurationModel model = (NetworkConfigurationModel) ((NetworkConfigurationModelEditPart) newInput).resolveSemanticElement();
			context = model.getSimulationContext();
			if (context == null) return;
			propertyModel = context.getStatistics();
			onSimulationStatisticsInput(context.getStatistics());
		}
		
	}
	
	void onLinkInfoInput(ILinkInfo info) {
		LinkStatistics linkStat = context.getStatistics().getLinkStats(info.getLink());
		items.clear();
		items.add(new InfoTableItem("Name", info.getLink().getName()));
		items.add(new InfoTableItem("Status", info.isBroken() ? "fault" : "ok"));
		items.add(new InfoTableItem("Load %", new Double(info.getUsageValue() * 100.0).toString()));
		items.add(new InfoTableItem("Data to transmit", String.valueOf(info.getAttemptedToTransferPerStep())));
		String dataInfo = linkStat.dataFailed + " / " + linkStat.dataTransmitted + " ; " + ((double)linkStat.dataFailed / (double)linkStat.dataTransmitted);
		items.add(new InfoTableItem("Failed / Transmitted ; %", dataInfo));
//		items.add(new InfoTableItem("Total size of transmitted messages", String.valueOf(info.getSizeOfTransmittedMessages())));
//		items.add(new InfoTableItem("Average size of transmitted messages", String.valueOf(info.getAverageSizeOfTransmittedMessages())));
		items.add(new InfoTableItem("Average usage", String.valueOf(linkStat.totalAverageUsage)));
		items.add(new InfoTableItem("Imporatance", String.valueOf(linkStat.importance)));
		items.add(new InfoTableItem("% of time when channel is fully loaded", String.valueOf(linkStat.timeLinkIsFull)));
	}
	
	void onNodeInfoInput(INodeInfo info) {
		NodeStatistics nodeStat = context.getStatistics().getNodeStats(info.getNode());
		items.clear();
		items.add(new InfoTableItem("Node name", info.getNode().getName()));
		items.add(new InfoTableItem("Status", info.isBroken() ? "fault" : "ok"));
		String dataInfo = nodeStat.dataFailed + " / " + nodeStat.dataTransmitted + " ; " + ((double)nodeStat.dataFailed / (double)nodeStat.dataTransmitted);
		items.add(new InfoTableItem("Failed / Transmitted ; %", dataInfo));
		items.add(new InfoTableItem("Queue overflow faults", Integer.toString(nodeStat.queueOverflowFaults)));
		//		items.add(new InfoTableItem("Number of transmitted messages", String.valueOf(info.getNumberOfTransmittedMessages())));
//		items.add(new InfoTableItem("Number of generated in node transmitted messages", String.valueOf(info.getNumberOfGeneratedTransmittedMessages())));
//		items.add(new InfoTableItem("Number of transmitted transit messages", String.valueOf(info.getNumberOfTransitTransmittedMessages())));
//		items.add(new InfoTableItem("Total size of transmitted messages", String.valueOf(info.getTotalSizeOfTransmittedMessages())));
//		items.add(new InfoTableItem("Total size of generated in node transmitted messages", String.valueOf(info.getTotalSizeOfGeneratedTransmittedMessages())));
//		items.add(new InfoTableItem("Total size of transmitted transit messages", String.valueOf(info.getTotalSizeOfTransitTransmittedMessages())));
//		items.add(new InfoTableItem("Average size of transmitted messages", String.valueOf(info.getAverageSizeOfTransmittedMessages())));
//		items.add(new InfoTableItem("Average size of generated in node transmitted messages", String.valueOf(info.getAverageSizeOfGeneratedTransmittedMessages())));
//		items.add(new InfoTableItem("Average size of transmitted transit messages", String.valueOf(info.getAverageSizeOfTransitTransmittedMessages())));
	}
	
	void onSimulationStatisticsInput(SimulationStatistics stats) {
		if (stats == null) return;
		items.clear();
		items.add(new InfoTableItem("Messages created", Integer.toString(stats.getMessagesCreated())));
		items.add(new InfoTableItem("Messages delivered", Integer.toString(stats.getMessagedDelivered())));
	}

	public void refresh() {
		if (propertyModel instanceof INodeInfo) {
			onNodeInfoInput((INodeInfo) propertyModel);
		} else if (propertyModel instanceof ILinkInfo) {
			onLinkInfoInput((ILinkInfo) propertyModel);
		} else if (propertyModel instanceof SimulationStatistics) {
			onSimulationStatisticsInput((SimulationStatistics) propertyModel);
		}
	}
	
	public void refreshForced() {
		inputChanged(null, input, input);
	}
}
